#include <Kharlia/Engine/Common.h>
#include <Kharlia/Engine/Init.h>
#include <Kharlia/Engine/Level.h>

namespace kharlia { namespace engine {

void _InitLevelBindings() {
    def("TileFromCoords", &TileFromCoords);
    def("TileToX", &TileToX);
    def("TileToY", &TileToY);

    class_<FTileLayer, shared_ptr<FTileLayer>, bases<core::CObject>, boost::noncopyable>
        ("FTileLayer", init<int>())
        .def(init<int, const FSizeI&>())
        .def(init<int, shared_ptr<FTileData>>())
        .def_readonly("Index", &FTileLayer::mIndex)
        .def_readonly("TileData", &FTileLayer::mTileData)
        .def_pickle(PSFTileLayer())
        ;

    class_<FTileGroup, shared_ptr<FTileGroup>, bases<core::CObject>, boost::noncopyable>
        ("FTileGroup", init<const FSizeI&>())
        .def_readonly("WIDTH", &FTileGroup::WIDTH)
        .def_readonly("HEIGHT", &FTileGroup::HEIGHT)
        .def("AddLayer", (void (FTileGroup::*)(int))&FTileGroup::AddLayer)
        .def("AddLayer", (void (FTileGroup::*)(int, shared_ptr<FTileLayer>))&FTileGroup::AddLayer)
        .def("GetLayer", &FTileGroup::GetLayer, return_value_policy<copy_const_reference>())
        .def("GetLayerIndices", &FTileGroup::GetLayerIndicesPy)
        .add_property("LayerCount", &FTileGroup::GetLayerCount)
        .def_readonly("Size", &FTileGroup::mSize)
        .def_pickle(PSFTileGroup())
        ;

    class_<FLayerInfo, shared_ptr<FLayerInfo>>
        ("FLayerInfo", init<>())
        .def_readwrite("Index", &FLayerInfo::Index)
        .def_readwrite("Visible", &FLayerInfo::Visible)
        .def_readwrite("NoCollision", &FLayerInfo::NoCollision)
        .def_readwrite("Red", &FLayerInfo::Red)
        .def_readwrite("Green", &FLayerInfo::Green)
        .def_readwrite("Blue", &FLayerInfo::Blue)
        .def_readwrite("Alpha", &FLayerInfo::Alpha)
        .def_readwrite("Color", &FLayerInfo::Color)
        .def_pickle(PSFLayerInfo())
        ;

    class_<FTileInfo>
        ("FTileInfo", init<>())
        .add_property("Blocking", &FTileInfo::GetBlocking, &FTileInfo::SetBlocking)
        .add_property("Shape", &FTileInfo::GetShape, &FTileInfo::SetShape)
        ;

    class_<CLevel, shared_ptr<CLevel>, bases<core::CObject>, boost::noncopyable>
        ("CLevelBase", init<>())
        .def_readonly("MAX_WIDTH", &CLevel::MAX_WIDTH)
        .def_readonly("MAX_HEIGHT", &CLevel::MAX_HEIGHT)
        .def_readonly("World", &CLevel::mWorld)
        .def_readonly("Size", &CLevel::mSize)
        .def_readonly("TileGroupSize", &CLevel::mTileGroupSize)
        .add_property("TileGroupCount", &CLevel::GetTileGroupCount)
        .add_property("LayerInfoCount", &CLevel::GetLayerInfoCount)
        .add_property("LayerInfoIndices", &CLevel::GetLayerInfoIndicesPy)
        .def_readonly("Name", &CLevel::mName)
        .def_readonly("GUID", &CLevel::mGUID)
        .add_property("ActorCount", &CLevel::GetActorCount)
        .def_readonly("ActorTasker", &CLevel::mActorTasker)
        .def("Init", &CLevel::Init)
        .def("Exit", &CLevel::Exit)
        .def("Test", &CLevel::Test)
        .def("ActorTickerMain", &CLevel::ActorTickerMain)
        .def("Tick", &CLevel::Tick)
        .def("TickActors", &CLevel::TickActors)
        .def("GetActorByTag", &CLevel::GetActorByTag)
        .def("GetActorByID", &CLevel::GetActorByID)
        .def("GetActorByIndex", &CLevel::GetActorByIndex, return_value_policy<return_by_value>())
        .def("CreateActor", &CLevel::CreateActor, (arg("comps")=object(), arg("owner")=shared_ptr<CActor>(), arg("obj")=shared_ptr<CActor>()))
        .def("DestroyActor", &CLevel::DestroyActor)
        .def("CreatePlayerActor", &CLevel::CreatePlayerActor)
        .def("CreateLayer", &CLevel::CreateLayer)
        .def("GetTileGroup", (const shared_ptr<FTileGroup>& (CLevel::*)(uint) const)&CLevel::GetTileGroup, return_value_policy<copy_const_reference>())
        .def("GetTileGroup", (const shared_ptr<FTileGroup>& (CLevel::*)(const FVector2I&) const)&CLevel::GetTileGroup, return_value_policy<copy_const_reference>())
        .def("GetTileGroupAt", (const shared_ptr<FTileGroup>& (CLevel::*)(const FVector2I&) const)&CLevel::GetTileGroupAt, return_value_policy<copy_const_reference>())
        .def("GetTileGroupAt", (const shared_ptr<FTileGroup>& (CLevel::*)(const FVector2F&) const)&CLevel::GetTileGroupAt, return_value_policy<copy_const_reference>())
        .def("GetLayerInfo", &CLevel::GetLayerInfo)
        .def("GetTileInfo", (const FTileInfo* (CLevel::*)(int, const FVector2I&) const)&CLevel::GetTileInfo, return_internal_reference<>())
        .def("GetTileInfo", (const FTileInfo* (CLevel::*)(int) const)&CLevel::GetTileInfo, return_internal_reference<>())
        .def("SetTiles", (void (CLevel::*)(int, tile_t))&CLevel::SetTiles)
        .def("SetTiles", (void (CLevel::*)(int, const FVector2I&, const FSizeI&, tile_t))&CLevel::SetTiles)
        .def("SetTiles", (void (CLevel::*)(int, const FVector2I&, shared_ptr<FTileData>))&CLevel::SetTiles)
        .def("OnCreated", &CLevel::_OnCreated)
        .def("OnDestroyed", &CLevel::_OnDestroyed)
        .def("OnGameStarted", &CLevel::OnGameStarted)
        .def("OnGameStopped", &CLevel::OnGameStopped)
        .def("SetPlayerControllerClass", &CLevel::SetPlayerControllerClass).staticmethod("SetPlayerControllerClass")
        .def("GetActorClass", &CLevel::GetActorClass).staticmethod("GetActorClass")
        .def("SetActorClass", &CLevel::SetActorClass).staticmethod("SetActorClass")
        .def_pickle(PSCLevel())
        .setattr("PRE_TICK_GROUP", CLevel::PRE_TICK_GROUP)
        .setattr("TICK_GROUP", CLevel::TICK_GROUP)
        .setattr("POST_TICK_GROUP", CLevel::POST_TICK_GROUP)
        .setattr("GROUP_COUNT", CLevel::GROUP_COUNT)
        ;

    KH_IMPL_GC(CLevel);
}

}}